#region Copyright (c) 2006-2012 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2012 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion

using System;
using System.Linq;
using System.Text;
using Widgetsphere.Generator.Common;
using Widgetsphere.Generator.Models;

namespace Widgetsphere.Generator.EFDAL.Generators.Contexts
{
	public class ContextGeneratedTemplate : EFDALBaseTemplate
	{
		private readonly StringBuilder sb = new StringBuilder();

		public ContextGeneratedTemplate(ModelRoot model)
		{
			_model = model;
		}

		#region BaseClassTemplate overrides
		public override string FileName
		{
			get { return _model.ProjectName + "Entities.Generated.cs"; }
		}

		public string ParentItemName
		{
			get { return _model.ProjectName + "Entities.cs"; }
		}

		public override string FileContent
		{
			get
			{
				try
				{
					GenerateContent();
					return sb.ToString();
				}
				catch (Exception ex)
				{
					//System.Windows.Forms.MessageBox.Show(ex.ToString());
					throw;
				}
			}
		}
		#endregion

		#region GenerateContent

		private void GenerateContent()
		{
			try
			{
				Widgetsphere.Generator.GenerationHelper.AppendCopyrightInCode(sb, _model);
				this.AppendUsingStatements();
				AppendEDMMetaData();
				sb.AppendLine("namespace " + this.GetLocalNamespace());
				sb.AppendLine("{");
				this.AppendTableMapping();
				this.AppendTypeTableEnums();
				this.AppendClass();
				sb.AppendLine("}");
				sb.AppendLine();
				
				sb.AppendLine("namespace " + this.GetLocalNamespace() + ".Entity");
				sb.AppendLine("{");
				//this.AppendTypeTableWrappers();
				sb.AppendLine("}");
				sb.AppendLine();

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		private void AppendTableMapping()
		{
			sb.AppendLine("	#region EntityMappingConstants Enumeration");
			sb.AppendLine();
			sb.AppendLine("	/// <summary>");
			sb.AppendLine("	/// A map for all entity types in this library");
			sb.AppendLine("	/// </summary>");
			sb.AppendLine("	public enum EntityMappingConstants");
			sb.AppendLine("	{");

			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// A mapping for the the " + table.PascalName + " entity");
				sb.AppendLine("		/// </summary>");
				sb.AppendLine("		" + table.PascalName + ",");
			}

			sb.AppendLine("	}");
			sb.AppendLine();
			sb.AppendLine("	#endregion");
			sb.AppendLine();
		}

		private void AppendEDMMetaData()
		{
			try
			{
				sb.AppendLine("[assembly: EdmSchemaAttribute()]");
				sb.AppendLine("#region EDM Relationship Metadata");
				sb.AppendLine();

				foreach (var relation in _model.Database.Relations.Where(x => x.IsGenerated))
				{
					var parentTable = (Table)relation.ParentTableRef.Object;
					var childTable = (Table)relation.ChildTableRef.Object;
					if (
						parentTable.Generated &&
						childTable.Generated &&
						!childTable.AssociativeTable &&
						(!childTable.IsInheritedFrom(parentTable)))
					{
						if (relation.IsOneToOne && relation.AreAllFieldsPK)
							sb.AppendLine("[assembly: EdmRelationshipAttribute(\"" + this.GetLocalNamespace() + ".Entity" + "\", \"FK_" + relation.PascalRoleName + "_" + childTable.PascalName + "_" + parentTable.PascalName + "\", \"" + relation.PascalRoleName + parentTable.PascalName + "\", System.Data.Metadata.Edm.RelationshipMultiplicity." + (relation.IsRequired ? "One" : "ZeroOrOne") + ", typeof(" + this.GetLocalNamespace() + ".Entity." + parentTable.PascalName + "), \"" + relation.PascalRoleName + childTable.PascalName + "\", System.Data.Metadata.Edm.RelationshipMultiplicity.ZeroOrOne, typeof(" + this.GetLocalNamespace() + ".Entity." + childTable.PascalName + "), true)]");
						else
							sb.AppendLine("[assembly: EdmRelationshipAttribute(\"" + this.GetLocalNamespace() + ".Entity" + "\", \"FK_" + relation.PascalRoleName + "_" + childTable.PascalName + "_" + parentTable.PascalName + "\", \"" + relation.PascalRoleName + parentTable.PascalName + "\", System.Data.Metadata.Edm.RelationshipMultiplicity." + (relation.IsRequired ? "One" : "ZeroOrOne") + ", typeof(" + this.GetLocalNamespace() + ".Entity." + parentTable.PascalName + "), \"" + relation.PascalRoleName + childTable.PascalName + "List\", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(" + this.GetLocalNamespace() + ".Entity." + childTable.PascalName + "), true)]");
					}
				}

				//Add the associative table links
				foreach (var table in _model.Database.Tables.Where(x => x.Generated && x.AssociativeTable).OrderBy(x => x.PascalName))
				{
					var associativeRelations = table.GetRelationsWhereChild().ToList();
					if (associativeRelations.Count == 0)
					{
						System.Diagnostics.Debug.Write(string.Empty);
					}
					else
					{
						var relation1 = associativeRelations.First();
						var relation2 = associativeRelations.Last();
						var table1 = relation1.ParentTableRef.Object as Table;
						var table2 = relation2.ParentTableRef.Object as Table;
						//if (table1.Generated && table2.Generated && !table1.IsTypeTable && !table2.IsTypeTable)
						if (table1.Generated && table2.Generated)
							sb.AppendLine("[assembly: EdmRelationshipAttribute(\"" + this.GetLocalNamespace() + ".Entity" + "\", \"" + table.PascalName + "\", \"" + relation1.PascalRoleName + table1.PascalName + "List\", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(" + this.GetLocalNamespace() + ".Entity." + table1.PascalName + "), \"" + relation2.PascalRoleName + table2.PascalName + "List\", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(" + this.GetLocalNamespace() + ".Entity." + table2.PascalName + "))]");
					}
				}

				sb.AppendLine();
				sb.AppendLine("#endregion");
				sb.AppendLine();
			}
			catch (Exception ex)
			{
				throw;
			}
		}

		private void AppendUsingStatements()
		{
			sb.AppendLine("using System;");
			sb.AppendLine("using System.Linq;");
			sb.AppendLine("using System.Data.Objects;");
			sb.AppendLine("using System.Data.Objects.DataClasses;");
			sb.AppendLine("using System.ComponentModel;");
			sb.AppendLine("using System.Runtime.Serialization;");
			sb.AppendLine("using System.Collections.Generic;");
			sb.AppendLine("using " + this.GetLocalNamespace() + ".Entity;");
			sb.AppendLine();
		}

		private void AppendClass()
		{
			sb.AppendLine("	#region Entity Context");
			sb.AppendLine();
			sb.AppendLine("	/// <summary>");
			sb.AppendLine("	/// There context " + _model.ProjectName + "Entities");
			sb.AppendLine("	/// </summary>");
			sb.AppendLine("	[System.CodeDom.Compiler.GeneratedCode(\"nHydrateModelGenerator\", \"" + _model.ModelToolVersion + "\")]");
			sb.AppendLine("	public partial class " + _model.ProjectName + "Entities : System.Data.Objects.ObjectContext, " + this.GetLocalNamespace() + ".Interfaces.I" + _model.ProjectName + "Entities");
			sb.AppendLine("	{");

			//Create the modifier property
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// The audit modifier used to mark database edits");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		protected ContextStartup _contextStartup = new ContextStartup(null);");
			sb.AppendLine();

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Initializes a new " + _model.ProjectName + "Entities object using the connection string found in the '" + _model.ProjectName + "Entities' section of the application configuration file.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public " + _model.ProjectName + "Entities() :");
			sb.AppendLine("			base(\"name=" + _model.ProjectName + "Entities\", \"" + _model.ProjectName + "Entities\")");
			sb.AppendLine("		{");
			sb.AppendLine("			this.OnContextCreated();");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Initialize a new " + _model.ProjectName + "Entities object with an audit modifier.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public " + _model.ProjectName + "Entities(ContextStartup contextStartup) :");
			sb.AppendLine("			base(\"name=" + _model.ProjectName + "Entities\", \"" + _model.ProjectName + "Entities\")");
			sb.AppendLine("		{");
			sb.AppendLine("			_contextStartup = contextStartup;");
			sb.AppendLine("			this.ContextOptions.LazyLoadingEnabled = contextStartup.AllowLazyLoading;");
			sb.AppendLine("			this.CommandTimeout = contextStartup.CommandTimeout;");
			sb.AppendLine("			this.OnContextCreated();");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Initialize a new " + _model.ProjectName + "Entities object.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public " + _model.ProjectName + "Entities(string connectionString) :");
			sb.AppendLine("			base(connectionString, \"" + _model.ProjectName + "Entities\")");
			sb.AppendLine("		{");
			sb.AppendLine("			this.OnContextCreated();");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Initialize a new " + _model.ProjectName + "Entities object.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public " + _model.ProjectName + "Entities(System.Data.EntityClient.EntityConnection connection) :");
			sb.AppendLine("			base(connection, \"" + _model.ProjectName + "Entities\")");
			sb.AppendLine("		{");
			sb.AppendLine("			this.OnContextCreated();");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		partial void OnContextCreated();");
			sb.AppendLine();

			sb.AppendLine("		partial void OnContextCreated()");
			sb.AppendLine("		{");
			sb.AppendLine("			// set the Context reference whenever an entity is loaded");
			sb.AppendLine("			this.ObjectMaterialized += (sender, e) =>");
			sb.AppendLine("			{");
			sb.AppendLine("				var o = ((e.Entity as Widgetsphere.EFCore.DataAccess.IReadOnlyBusinessObject) as IEntityWithContext);");
			sb.AppendLine("				if (o != null) o.Context = this;");
			sb.AppendLine("			};");
			sb.AppendLine("		}");
			sb.AppendLine();

			#region Tables
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// ");
				sb.AppendLine("		/// </summary>");

				if (table.ParentTable != null)
				{
					sb.AppendLine("		public virtual System.Data.Objects.ObjectQuery<" + table.PascalName + "> " + table.PascalName + "");
					sb.AppendLine("		{");
					sb.AppendLine("			get { return this." + table.GetAbsoluteBaseTable().PascalName + ".OfType<" + table.PascalName + ">(); }");
					sb.AppendLine("		}");
				}
				else
				{
					sb.AppendLine("		public virtual System.Data.Objects.ObjectSet<" + this.GetLocalNamespace() + ".Entity." + table.PascalName + "> " + table.PascalName + "");
					sb.AppendLine("		{");
					sb.AppendLine("			get");
					sb.AppendLine("			{");
					sb.AppendLine("				lock (_locker" + table.CamelName + ")");
					sb.AppendLine("				{");
					sb.AppendLine("					if ((this._" + table.CamelName + " == null))");
					sb.AppendLine("					{");
					sb.AppendLine("						this._" + table.CamelName + " = base.CreateObjectSet<" + this.GetLocalNamespace() + ".Entity." + table.PascalName + ">(\"" + table.PascalName + "\");");
					sb.AppendLine("					}");
					sb.AppendLine("					return this._" + table.CamelName + ";");
					sb.AppendLine("				}");
					sb.AppendLine("			}");
					sb.AppendLine("		}");
					sb.AppendLine();
					sb.AppendLine("		private object _locker" + table.CamelName + " = new object();");
					sb.AppendLine();
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// The internal reference variable for the '" + table.PascalName + "' object set");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		protected System.Data.Objects.ObjectSet<" + this.GetLocalNamespace() + ".Entity." + table.PascalName + "> _" + table.CamelName + ";");
				}
				sb.AppendLine();
			}
			#endregion

			#region Views
			foreach (var view in _model.Database.CustomViews.Where(x => x.Generated).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// ");
				sb.AppendLine("		/// </summary>");

				sb.AppendLine("		public virtual System.Data.Objects.ObjectSet<" + this.GetLocalNamespace() + ".Entity." + view.PascalName + "> " + view.PascalName + "");
				sb.AppendLine("		{");
				sb.AppendLine("			get");
				sb.AppendLine("			{");
				sb.AppendLine("				lock (_locker" + view.CamelName + ")");
				sb.AppendLine("				{");
				sb.AppendLine("					if ((this._" + view.CamelName + " == null))");
				sb.AppendLine("					{");
				sb.AppendLine("						this._" + view.CamelName + " = base.CreateObjectSet<" + this.GetLocalNamespace() + ".Entity." + view.PascalName + ">(\"" + view.PascalName + "\");");
				sb.AppendLine("					}");
				sb.AppendLine("					return this._" + view.CamelName + ";");
				sb.AppendLine("				}");
				sb.AppendLine("			}");
				sb.AppendLine("		}");
				sb.AppendLine();
				sb.AppendLine("		private object _locker" + view.CamelName + " = new object();");
				sb.AppendLine();
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// The internal reference variable for the '" + view.PascalName + "' object set");
				sb.AppendLine("		/// </summary>");
				sb.AppendLine("		protected System.Data.Objects.ObjectSet<" + this.GetLocalNamespace() + ".Entity." + view.PascalName + "> _" + view.CamelName + ";");
				sb.AppendLine();
			}
			#endregion

			#region Scaler Functions

			foreach (var function in _model.Database.Functions.Where(x => !x.IsTable))
			{
				var returnColumn = function.Columns.First().Object as FunctionColumn;
				var parameterList = function.GetParameters().Where(x => x.Generated).ToList();

				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// " + function.Description.Replace("\"", "\\\""));
				sb.AppendLine("		/// </summary>");
				sb.Append("		public " + returnColumn.GetCodeType() + " " + function.PascalName + "(");
				sb.Append(string.Join(", ", parameterList.Select(x => x.GetCodeType() + " " + x.CamelName).ToList().ToArray()));
				sb.AppendLine(")");
				sb.AppendLine("		{");
				sb.AppendLine("			var paramArray = new List<System.Data.Objects.ObjectParameter>();");

				foreach (var parameter in parameterList)
				{
					if (parameter.AllowNull)
					{
						sb.AppendLine("			System.Data.Objects.ObjectParameter " + parameter.CamelName + "Parameter = null;");
						sb.AppendLine("			if (" + parameter.CamelName + " != null) { " + parameter.CamelName + "Parameter = new System.Data.Objects.ObjectParameter(\"" + parameter.DatabaseName + "\", " + parameter.CamelName + "); }");
						sb.AppendLine("			else { " + parameter.CamelName + "Parameter = new System.Data.Objects.ObjectParameter(\"" + parameter.DatabaseName + "\", typeof(" + parameter.GetCodeType() + ")); }");
						sb.AppendLine("			paramArray.Add(" + parameter.CamelName + "Parameter);");
					}
					else
					{
						sb.AppendLine("			paramArray.Add(new System.Data.Objects.ObjectParameter(\"" + parameter.DatabaseName + "\", " + parameter.CamelName + "));");
					}
				}

				sb.Append("			return this.CreateQuery<" + returnColumn.GetCodeType() + ">(\"SELECT VALUE " + this.DefaultNamespace + ".EFDAL.Store." + function.DatabaseName + "(");
				sb.Append(string.Join(", ", parameterList.Select(x => "@" + x.DatabaseName).ToList().ToArray()));
				sb.AppendLine(") FROM {1}\", paramArray.ToArray()).First();");
				sb.AppendLine("		}");
				sb.AppendLine();
			}

			#endregion

			#region Add Functionality
			//Add an strongly-typed extension for "AddItem" method
			sb.AppendLine("		#region AddItem Methods");
			sb.AppendLine();

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Adds an entity to the object context");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		/// <param name=\"entity\"></param>");
			sb.AppendLine("		public virtual void AddItem(Widgetsphere.EFCore.DataAccess.IBusinessObject entity)");
			sb.AppendLine("		{");
			sb.AppendLine("			this.AddItem(entity);");
			sb.AppendLine("		}");
			sb.AppendLine();

			#region Tables
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable && !x.Immutable).OrderBy(x => x.PascalName)) // && !x.IsTypeTable
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// Adds an entity of type '" + table.PascalName + "' to the object context.");
				sb.AppendLine("		/// </summary>");
				sb.AppendLine("		/// <param name=\"entity\">The entity to add</param>");
				sb.AppendLine("		public virtual void AddItem(" + this.DefaultNamespace + ".EFDAL.Interfaces.Entity.I" + table.PascalName + " entity)");
				sb.AppendLine("		{");

				sb.AppendLine("			if (entity is " + GetLocalNamespace() + ".Entity." + table.PascalName + ")");
				sb.AppendLine("			{");
				if (table.AllowCreateAudit)
					sb.AppendLine("				((" + GetLocalNamespace() + ".Entity." + table.PascalName + ")entity)." + _model.Database.CreatedByPascalName + " = _contextStartup.Modifer;");
				if (table.AllowModifiedAudit)
					sb.AppendLine("				((" + GetLocalNamespace() + ".Entity." + table.PascalName + ")entity)." + _model.Database.ModifiedByPascalName + " = _contextStartup.Modifer;");
				sb.AppendLine("			}");

				if (table.ParentTable == null)
					sb.AppendLine("			base.AddObject(\"" + table.PascalName + "\", entity);");
				else
					sb.AppendLine("			base.AddObject(\"" + table.GetAbsoluteBaseTable().PascalName + "\", entity);");
				sb.AppendLine("		}");
				sb.AppendLine();
			}
			#endregion

			#region Views
			foreach (var view in _model.Database.CustomViews.Where(x => x.Generated).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// Adds an entity of type '" + view.PascalName + "' to the object context.");
				sb.AppendLine("		/// </summary>");
				sb.AppendLine("		/// <param name=\"entity\">The entity to add</param>");
				sb.AppendLine("		public virtual void AddItem(" + this.GetLocalNamespace() + ".Entity." + view.PascalName + " entity)");
				sb.AppendLine("		{");
				sb.AppendLine("			base.AddObject(\"" + view.PascalName + "\", entity);");
				sb.AppendLine("		}");
				sb.AppendLine();
			}
			#endregion

			//Overload the original signature as an error
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Adds an object to the object context.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		[Obsolete(\"This method signature is no longer used. Use the AddItem method.\", true)]");
			sb.AppendLine("		[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]");
			sb.AppendLine("		public new void AddObject(string entitySetName, object entity)");
			sb.AppendLine("		{");
			sb.AppendLine("			throw new Exception(\"This method signature is no longer used. Use the AddItem method.\");");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		#endregion");
			sb.AppendLine();
			#endregion

			#region Delete Functionality
			//Add an strongly-typed extension for "DeleteItem" method
			sb.AppendLine("		#region DeleteItem Methods");
			sb.AppendLine();

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Marks an entity for deletion.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		/// <param name=\"entity\">An enttiy to delete. The object can be in any state except System.Data.EntityState.Detached.</param>");
			sb.AppendLine("		public virtual void DeleteItem(Widgetsphere.EFCore.DataAccess.IBusinessObject entity)");
			sb.AppendLine("		{");
			var index = 0;
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable && !x.IsTypeTable && !x.Immutable))
			{
				sb.Append("			");
				if (index > 0) sb.Append("else ");
				sb.AppendLine("if (entity is " + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + ") base.DeleteObject(entity);");
				index++;
			}
			sb.AppendLine("			else throw new Exception(\"An entity of this type cannot deleted!\");");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Marks a set of entities for deletion.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		/// <param name=\"entityList\">A list of NHEntityObject objects to mark for deletion</param>");
			sb.AppendLine("		public virtual void DeleteItem(IEnumerable<Widgetsphere.EFCore.DataAccess.IBusinessObject> entityList)");
			sb.AppendLine("		{");
			sb.AppendLine("			foreach (var item in entityList)");
			sb.AppendLine("			{");
			sb.AppendLine("				entityList.ToList().ForEach(x => this.DeleteItem(x));");
			sb.AppendLine("			}");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Marks an object for deletion.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		[Obsolete(\"This method signature is no longer used. Use the AddItem method.\", true)]");
			sb.AppendLine("		[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]");
			sb.AppendLine("		public new void DeleteObject(object entity)");
			sb.AppendLine("		{");
			sb.AppendLine("			this.DeleteItem((Widgetsphere.EFCore.DataAccess.IBusinessObject)entity);");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		#endregion");
			sb.AppendLine();
			#endregion

			#region Connection String
			sb.AppendLine("		internal static string GetConnectionString()");
			sb.AppendLine("		{");
			sb.AppendLine("			string s = System.Configuration.ConfigurationManager.ConnectionStrings[\"" + _model.ProjectName + "Entities\"].ConnectionString;");
			sb.AppendLine("			System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex(\"provider connection string\\\\s*=\\\\s*\\\"([^\\\"]*)\");");
			sb.AppendLine("			System.Text.RegularExpressions.Match m = regEx.Match(s);");
			sb.AppendLine("			string connString = string.Empty;");
			sb.AppendLine("			if (m != null && m.Groups.Count > 1)");
			sb.AppendLine("			{");
			sb.AppendLine("				connString = m.Groups[1].Value;");
			sb.AppendLine("			}");
			sb.AppendLine("			return connString;");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		private string GetConnString()");
			sb.AppendLine("		{");
			sb.AppendLine("			string s = this.Connection.ConnectionString;");
			sb.AppendLine("			System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex(\"provider connection string\\\\s*=\\\\s*\\\"([^\\\"]*)\");");
			sb.AppendLine("			System.Text.RegularExpressions.Match m = regEx.Match(s);");
			sb.AppendLine("			string connString = string.Empty;");
			sb.AppendLine("			if (m != null && m.Groups.Count > 1)");
			sb.AppendLine("			{");
			sb.AppendLine("				connString = m.Groups[1].Value;");
			sb.AppendLine("			}");
			sb.AppendLine("			return connString;");
			sb.AppendLine("		}");
			sb.AppendLine();
			#endregion

			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// The global settings of this context");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public ContextStartup ContextStartup");
			sb.AppendLine("		{");
			sb.AppendLine("			get { return _contextStartup; }");
			sb.AppendLine("		}");
			sb.AppendLine();

			sb.AppendLine("		#region I" + _model.ProjectName + " Members");
			sb.AppendLine();
			sb.AppendLine("		void " + this.GetLocalNamespace() + ".Interfaces.I" + _model.ProjectName + "Entities.AddItem(Widgetsphere.EFCore.DataAccess.IBusinessObject entity)");
			sb.AppendLine("		{");
			index = 0;
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable && !x.IsTypeTable && !x.Immutable).OrderBy(x => x.PascalName))
			{
				sb.Append("			");
				if (index > 0) sb.Append("else ");
				sb.Append("if (entity is " + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + ") ");
				sb.AppendLine("this.AddItem((" + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + ")entity);");
				index++;
			}
			sb.AppendLine("			else throw new Exception(\"Entity type not found\");");
			sb.AppendLine("		}");
			sb.AppendLine();

			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		System.Data.Objects.IObjectSet<" + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + "> " + this.GetLocalNamespace() + ".Interfaces.I" + _model.ProjectName + "Entities." + table.PascalName);
				sb.AppendLine("		{");
				sb.AppendLine("			get { return (System.Data.Objects.IObjectSet<" + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + ">)this." + table.PascalName + "; }");
				sb.AppendLine("		}");
				sb.AppendLine();
			}

			#region Stored Procedures
			foreach (var storedProcedure in _model.Database.CustomStoredProcedures.Where(x => x.Generated && x.Columns.Count > 0).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// ");
				sb.AppendLine("		/// </summary>");
				sb.Append("		public IEnumerable<" + storedProcedure.PascalName + "> " + storedProcedure.PascalName + "(");
				var parameterList = storedProcedure.GetParameters().Where(x => x.Generated).ToList();
				foreach (var parameter in parameterList)
				{
					if (parameter.IsOutputParameter) sb.Append("out ");
					sb.Append(parameter.GetCodeType() + " " + parameter.CamelName);
					if (parameterList.IndexOf(parameter) < parameterList.Count() - 1)
						sb.Append(", ");
				}
				sb.AppendLine(")");
				sb.AppendLine("		{");

				foreach (var parameter in parameterList)
				{
					if (parameter.IsOutputParameter)
					{
						sb.AppendLine("			var " + parameter.CamelName + "Parameter = new ObjectParameter(\"" + parameter.DatabaseName + "\", typeof(" + parameter.GetCodeType() + "));");
					}
					else if (parameter.AllowNull)
					{
						sb.AppendLine("			ObjectParameter " + parameter.CamelName + "Parameter = null;");
						sb.AppendLine("			if (" + parameter.CamelName + " != null) { " + parameter.CamelName + "Parameter = new ObjectParameter(\"" + parameter.DatabaseName + "\", " + parameter.CamelName + "); }");
						sb.AppendLine("			else { " + parameter.CamelName + "Parameter = new ObjectParameter(\"" + parameter.DatabaseName + "\", typeof(" + parameter.GetCodeType() + ")); }");
					}
					else
					{
						sb.AppendLine("			var " + parameter.CamelName + "Parameter = new ObjectParameter(\"" + parameter.DatabaseName + "\", " + parameter.CamelName + ");");
					}
				}

				sb.Append("			var retval = base.ExecuteFunction<" + storedProcedure.PascalName + ">(\"" + storedProcedure.GetDatabaseObjectName() + "\"");

				if (parameterList.Count > 0)
				{
					sb.Append(", ");
					foreach (var parameter in parameterList)
					{
						sb.Append(parameter.CamelName + "Parameter");
						if (parameterList.IndexOf(parameter) < parameterList.Count() - 1)
							sb.Append(", ");
					}
				}

				sb.AppendLine(").ToList();");

				//Add code here to handle output parameters
				foreach (var parameter in parameterList.Where(x => x.IsOutputParameter))
				{
					sb.AppendLine("			" + parameter.CamelName + " = (" + parameter.GetCodeType() + ")" + parameter.CamelName + "Parameter.Value;");
				}

				sb.AppendLine("			return retval;");

				sb.AppendLine("		}");
				sb.AppendLine();
			}

			//Stoed procs that are Action (no columns)
			foreach (var storedProcedure in _model.Database.CustomStoredProcedures.Where(x => x.Generated && x.Columns.Count == 0).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// Calls the " + storedProcedure.PascalName + " action");
				sb.AppendLine("		/// </summary>");
				sb.Append("		public void " + storedProcedure.PascalName + "(");

				index = 0;
				foreach (var param in storedProcedure.GetParameters())
				{
					sb.Append((param.IsOutputParameter ? "out " : string.Empty) + param.GetCodeType() + " " + param.CamelName);
					if (index < storedProcedure.Parameters.Count - 1)
						sb.Append(", ");
					index++;
				}

				sb.AppendLine(")");
				sb.AppendLine("		{");

				sb.AppendLine("			var parameters = new List<ObjectParameter>();");

				foreach (var param in storedProcedure.GetParameters())
				{
					if (param.IsOutputParameter)
						sb.AppendLine("			parameters.Add(new ObjectParameter(\"" + param.PascalName + "\", typeof(" + param.GetCodeType() + ")));");
					else
						sb.AppendLine("			parameters.Add(new ObjectParameter(\"" + param.PascalName + "\", " + param.CamelName + "));");
				}

				sb.AppendLine("			base.ExecuteFunction(\"" + _model.GetStoredProcedurePrefix(storedProcedure) + "" + storedProcedure.PascalName + "\", parameters.ToArray());");

				index = 0;
				foreach (var param in storedProcedure.GetParameters())
				{
					if (param.IsOutputParameter)
					{
						if (param.AllowNull)
							sb.AppendLine("			if (parameters[" + index + "].Value == System.DBNull.Value) " + param.CamelName + " = null; else " + param.CamelName + " = (" + param.GetCodeType() + ")parameters[" + index + "].Value;");
						else
							sb.AppendLine("			" + param.CamelName + " = (" + param.GetCodeType() + ")parameters[" + index + "].Value;");
					}
					index++;
				}

				sb.AppendLine("		}");
				sb.AppendLine();
			}

			#endregion

			sb.AppendLine("		void " + this.GetLocalNamespace() + ".Interfaces.I" + _model.ProjectName + "Entities.DeleteItem(IEnumerable<Widgetsphere.EFCore.DataAccess.IBusinessObject> entityList)");
			sb.AppendLine("		{");
			sb.AppendLine("			foreach (var entity in entityList)");
			sb.AppendLine("			{");
			sb.AppendLine("				this.DeleteItem(entity);");
			sb.AppendLine("			}");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		void " + this.GetLocalNamespace() + ".Interfaces.I" + _model.ProjectName + "Entities.DeleteItem(Widgetsphere.EFCore.DataAccess.IBusinessObject entity)");
			sb.AppendLine("		{");
			sb.AppendLine("			this.DeleteItem(entity);");
			sb.AppendLine("		}");
			sb.AppendLine("		#endregion");
			sb.AppendLine();

			#region Configuration API/Database verification
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Determines the version of the model that created this library.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public virtual string Version");
			sb.AppendLine("		{");

			var cacheFile = new Widgetsphere.Generator.Common.ModelCacheFile(_model.GeneratorProject);
			var genVersion = cacheFile.GeneratedVersion;
			sb.AppendLine("			get { return \"" + _model.Version + "." + genVersion + "\"; }");

			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Determines the key of the model that created this library.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public virtual string ModelKey");
			sb.AppendLine("		{");
			sb.AppendLine("			get { return \"" + _model.Key + "\"; }");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Determines if the API matches the database connection");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		/// <returns></returns>");
			sb.AppendLine("		public virtual bool IsValidConnection()");
			sb.AppendLine("		{");
			sb.AppendLine("			return IsValidConnection(true);");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Determines if the API matches the database connection");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		/// <param name=\"checkVersion\">Determines if the check also includes the exact version of the model</param>");
			sb.AppendLine("		/// <returns></returns>");
			sb.AppendLine("		public virtual bool IsValidConnection(bool checkVersion)");
			sb.AppendLine("		{");
			sb.AppendLine("			if (string.IsNullOrEmpty(GetConnectionString()))");
			sb.AppendLine("				return false;");
			sb.AppendLine();
			sb.AppendLine("			string modelKey = GetDatabaseExtendedProperty(GetConnectionString(), \"ModelKey\");");
			sb.AppendLine("			if (string.Compare(this.ModelKey, modelKey, true) != 0)");
			sb.AppendLine("				return false;");
			sb.AppendLine();
			sb.AppendLine("			if (checkVersion)");
			sb.AppendLine("			{");
			sb.AppendLine("				string dbVersion = GetDatabaseExtendedProperty(GetConnectionString(), \"dbVersion\");");
			sb.AppendLine("				if (dbVersion != this.Version)");
			sb.AppendLine("					return false;");
			sb.AppendLine("			}");
			sb.AppendLine();
			sb.AppendLine("			return true;");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		private static string GetDatabaseExtendedProperty(string connectionString, string propertyName)");
			sb.AppendLine("		{");
			sb.AppendLine("			string returnVal = string.Empty;");
			sb.AppendLine("			returnVal = SelectExtendedProperty(connectionString, propertyName, string.Empty, string.Empty, string.Empty);");
			sb.AppendLine("			return returnVal;");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		private static string SelectExtendedProperty(string connectionString, string property, string user, string table, string parameter)");
			sb.AppendLine("		{");
			sb.AppendLine("			string returnVal = string.Empty;");
			sb.AppendLine("			string userName = string.Empty;");
			sb.AppendLine("			string userValue = string.Empty;");
			sb.AppendLine("			string tableName = string.Empty;");
			sb.AppendLine("			string tableValue = string.Empty;");
			sb.AppendLine("			string columnName = string.Empty;");
			sb.AppendLine("			string columnValue = string.Empty;");
			sb.AppendLine();
			sb.AppendLine("			property = \"'\" + property + \"'\";");
			sb.AppendLine("			if (user == string.Empty)");
			sb.AppendLine("			{");
			sb.AppendLine("				userName = \"NULL\";");
			sb.AppendLine("				userValue = \"NULL\";");
			sb.AppendLine("			}");
			sb.AppendLine("			else");
			sb.AppendLine("			{");
			sb.AppendLine("				userName = \"'user'\";");
			sb.AppendLine("				userValue = \"'\" + user + \"'\";");
			sb.AppendLine("			}");
			sb.AppendLine("			if (table == string.Empty)");
			sb.AppendLine("			{");
			sb.AppendLine("				tableName = \"NULL\";");
			sb.AppendLine("				tableValue = \"NULL\";");
			sb.AppendLine("			}");
			sb.AppendLine("			else");
			sb.AppendLine("			{");
			sb.AppendLine("				tableName = \"'table'\";");
			sb.AppendLine("				tableValue = \"'\" + table + \"'\";");
			sb.AppendLine("			}");
			sb.AppendLine("			if (parameter == string.Empty)");
			sb.AppendLine("			{");
			sb.AppendLine("				columnName = \"NULL\";");
			sb.AppendLine("				columnValue = \"NULL\";");
			sb.AppendLine("			}");
			sb.AppendLine("			else");
			sb.AppendLine("			{");
			sb.AppendLine("				columnName = \"'parameter'\";");
			sb.AppendLine("				columnValue = \"'\" + parameter + \"'\";");
			sb.AppendLine("			}");
			sb.AppendLine();
			sb.AppendLine("			System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection();");
			sb.AppendLine("			System.Data.SqlClient.SqlDataReader externalReader = null;");
			sb.AppendLine("			try");
			sb.AppendLine("			{");
			sb.AppendLine("				conn.ConnectionString = connectionString;");
			sb.AppendLine("				conn.Open();");
			sb.AppendLine("				var cmdGetExtProp = new System.Data.SqlClient.SqlCommand();");
			sb.AppendLine("				cmdGetExtProp.CommandText = String.Format(\"SELECT value FROM ::fn_listextendedproperty({0}, {1}, {2}, {3}, {4}, {5}, {6})\", new object[] { property, userName, userValue, tableName, tableValue, columnName, columnValue });");
			sb.AppendLine("				cmdGetExtProp.CommandType = System.Data.CommandType.Text;");
			sb.AppendLine("				cmdGetExtProp.Connection = conn;");
			sb.AppendLine("				externalReader = cmdGetExtProp.ExecuteReader();");
			sb.AppendLine("				if (externalReader.Read())");
			sb.AppendLine("				{");
			sb.AppendLine("					if (externalReader[0] != System.DBNull.Value)");
			sb.AppendLine("					{");
			sb.AppendLine("						returnVal = externalReader.GetString(0);");
			sb.AppendLine("					}");
			sb.AppendLine("				}");
			sb.AppendLine("			}");
			sb.AppendLine("			catch (Exception ex)");
			sb.AppendLine("			{");
			sb.AppendLine("				throw ex;");
			sb.AppendLine("			}");
			sb.AppendLine("			finally");
			sb.AppendLine("			{");
			sb.AppendLine("				if (externalReader != null)");
			sb.AppendLine("					externalReader.Close();");
			sb.AppendLine("				if (conn != null)");
			sb.AppendLine("					conn.Close();");
			sb.AppendLine("			}");
			sb.AppendLine("			return returnVal;");
			sb.AppendLine("		}");
			sb.AppendLine();
			#endregion

			#region Auditing
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Persists all updates to the data source and resets change tracking in the object context.");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		/// <param name=\"options\"></param>");
			sb.AppendLine("		/// <returns>The number of objects in an System.Data.EntityState.Added, System.Data.EntityState.Modified, or System.Data.EntityState.Deleted state when System.Data.Objects.ObjectContext.SaveChanges() was called.</returns>");
			sb.AppendLine("		public override int SaveChanges(SaveOptions options)");
			sb.AppendLine("		{");
			sb.AppendLine("			//Process deleted list");
			sb.AppendLine("			var deletedList = this.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Deleted);");
			sb.AppendLine("			foreach (var item in deletedList)");
			sb.AppendLine("			{");
			sb.AppendLine("				var entity = item.Entity as Widgetsphere.EFCore.DataAccess.IAuditable;");
			sb.AppendLine("				if (entity != null)");
			sb.AppendLine("				{");
			sb.AppendLine("					if (entity.IsModifyAuditImplemented && entity.ModifiedBy != this.ContextStartup.Modifer)");
			sb.AppendLine("					{");
			sb.AppendLine("						System.Data.SqlClient.SqlConnection connection = null;");
			sb.AppendLine("						try");
			sb.AppendLine("						{");
			sb.AppendLine("							connection = new System.Data.SqlClient.SqlConnection(GetConnectionString());");
			sb.AppendLine("							connection.Open();");
			sb.AppendLine("							System.Data.SqlClient.SqlCommand command = null;");

			var index2 = 0;
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.IsTypeTable && !x.AssociativeTable && x.AllowModifiedAudit && x.AllowAuditTracking).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("							" + (index2 > 0 ? "else " : string.Empty) + "if (entity is " + this.GetLocalNamespace() + ".Entity." + table.PascalName + ")");
				sb.AppendLine("							{");
				sb.Append("								command = new System.Data.SqlClient.SqlCommand(\"UPDATE [" + table.GetSQLSchema() + "].[" + table.DatabaseName + "] SET [" + _model.Database.ModifiedByDatabaseName + "] = @mod WHERE ");

				var ii = 1;
				foreach (var column in table.PrimaryKeyColumns)
				{
					sb.Append("[" + column.DatabaseName + "] = @pk" + ii + " AND ");
					ii++;
				}
				sb.Append("(([" + _model.Database.ModifiedByDatabaseName + "] != @mod) OR ([" + _model.Database.ModifiedByDatabaseName + "] IS NULL AND @mod IS NOT NULL) OR ([" + _model.Database.ModifiedByDatabaseName + "] IS NOT NULL AND @mod IS NULL))");
				sb.AppendLine("\", connection);");

				ii = 1;
				foreach (var column in table.PrimaryKeyColumns)
				{
					sb.AppendLine("								command.Parameters.Add(new System.Data.SqlClient.SqlParameter(\"@pk" + ii + "\", ((" + this.GetLocalNamespace() + ".Entity." + table.PascalName + ")entity)." + column.PascalName + "));");
				}

				sb.AppendLine("							}");
				index2++;
			}

			sb.AppendLine("							if (command != null)");
			sb.AppendLine("							{");
			sb.AppendLine("								command.CommandType = System.Data.CommandType.Text;");
			sb.AppendLine("								if (this.ContextStartup.Modifer == null)");
			sb.AppendLine("									command.Parameters.Add(new System.Data.SqlClient.SqlParameter(\"@mod\", System.DBNull.Value));");
			sb.AppendLine("								else");
			sb.AppendLine("									command.Parameters.Add(new System.Data.SqlClient.SqlParameter(\"@mod\", this.ContextStartup.Modifer));");
			sb.AppendLine("								command.ExecuteNonQuery();");
			sb.AppendLine("							}");
			sb.AppendLine("						}");
			sb.AppendLine("						catch");
			sb.AppendLine("						{");
			sb.AppendLine("							throw;");
			sb.AppendLine("						}");
			sb.AppendLine("						finally");
			sb.AppendLine("						{");
			sb.AppendLine("							if (connection != null && connection.State == System.Data.ConnectionState.Open)");
			sb.AppendLine("								connection.Close();");
			sb.AppendLine("						}");
			sb.AppendLine("					}");
			sb.AppendLine("				}");
			sb.AppendLine("			}");
			sb.AppendLine();

			sb.AppendLine("			//Process added list");
			sb.AppendLine("			var addedList = this.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added);");
			sb.AppendLine("			foreach (var item in addedList)");
			sb.AppendLine("			{");
			sb.AppendLine("				var entity = item.Entity as Widgetsphere.EFCore.DataAccess.IAuditable;");
			sb.AppendLine("				if (entity != null)");
			sb.AppendLine("				{");
			sb.AppendLine("					if (entity.IsModifyAuditImplemented && entity.ModifiedBy != this.ContextStartup.Modifer)");
			sb.AppendLine("					{");

			var index3 = 0;
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.IsTypeTable && !x.AssociativeTable && x.AllowModifiedAudit).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("						" + (index3 > 0 ? "else " : string.Empty) + "if (entity is " + this.GetLocalNamespace() + ".Entity." + table.PascalName + ") ((" + this.GetLocalNamespace() + ".Entity." + table.PascalName + ")entity).ResetCreatedBy(this.ContextStartup.Modifer);");
				index3++;
			}
			sb.AppendLine("					}");
			sb.AppendLine("				}");
			sb.AppendLine("			}");
			sb.AppendLine();

			sb.AppendLine("			return base.SaveChanges(options);");
			sb.AppendLine("		}");
			sb.AppendLine();
			#endregion

			#region GetEntityFromField
			sb.AppendLine("		#region GetEntityFromField");
			sb.AppendLine();
			sb.AppendLine("		Enum Widgetsphere.EFCore.DataAccess.IContext.GetEntityFromField(Enum field)");
			sb.AppendLine("		{");
			sb.AppendLine("			return GetEntityFromField(field);");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		Widgetsphere.EFCore.DataAccess.IMetadata Widgetsphere.EFCore.DataAccess.IContext.GetMetaData(Enum entity)");
			sb.AppendLine("		{");
			sb.AppendLine("			return GetMetaData((EntityMappingConstants)entity);");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		System.Type Widgetsphere.EFCore.DataAccess.IContext.GetFieldType(Enum field)");
			sb.AppendLine("		{");
			sb.AppendLine("			return this.GetFieldType(field);");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Determines the entity from one of its fields");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public static EntityMappingConstants GetEntityFromField(Enum field)");
			sb.AppendLine("		{");
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable).OrderBy(x => x.PascalName))
			{
				sb.AppendLine("			if (field is " + this.GetLocalNamespace() + ".Entity." + table.PascalName + ".FieldNameConstants) return " + this.GetLocalNamespace() + ".EntityMappingConstants." + table.PascalName + ";");
			}
			sb.AppendLine("			throw new Exception(\"Unknown field type!\");");
			sb.AppendLine("		}");
			sb.AppendLine();
			#endregion

			#region GetMetaData
			sb.AppendLine("		/// <summary>");
			sb.AppendLine("		/// Gets the meta data object for an entity");
			sb.AppendLine("		/// </summary>");
			sb.AppendLine("		public static Widgetsphere.EFCore.DataAccess.IMetadata GetMetaData(" + this.GetLocalNamespace() + ".EntityMappingConstants table)");
			sb.AppendLine("		{");
			sb.AppendLine("			switch (table)");
			sb.AppendLine("			{");
			foreach (var table in _model.Database.Tables.Where(x => x.Generated && !x.AssociativeTable).OrderBy(x => x.PascalName))
			{
				sb.Append("				case " + this.GetLocalNamespace() + ".EntityMappingConstants." + table.PascalName + ": ");
				//sb.AppendLine("return Activator.CreateInstance(((System.ComponentModel.DataAnnotations.MetadataTypeAttribute)typeof(" + this.GetLocalNamespace() + ".Entity." + table.PascalName + ").GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.MetadataTypeAttribute), true).FirstOrDefault()).MetadataClassType) as " + this.GetLocalNamespace() + ".Interfaces.Entity.Metadata." + table.PascalName + "Metadata;");
				sb.AppendLine("return new " + GetLocalNamespace() + ".Interfaces.Entity.Metadata." + table.PascalName + "Metadata();");
			}
			sb.AppendLine("			}");
			sb.AppendLine("			throw new Exception(\"Entity not found!\");");
			sb.AppendLine("		}");
			sb.AppendLine();
			sb.AppendLine("		#endregion");
			sb.AppendLine();
			#endregion

			sb.AppendLine("	}");
			sb.AppendLine();


			sb.AppendLine("	#endregion");
			sb.AppendLine();

		}

		#region OLD CODE
		//private void AppendTypeTableWrappers()
		//{
		//  if (_model.Database.Tables.Count(x => x.IsTypeTable) == 0)
		//    return;

		//  sb.AppendLine("	#region Type Tables");
		//  sb.AppendLine();

		//  foreach (Table table in _model.Database.Tables.Where(x => x.IsTypeTable))
		//  {
		//    sb.AppendLine("	/// <summary>");
		//    sb.AppendLine("	/// The wrapper class for the type table '" + table.PascalName + "' used to define properties on related entities");
		//    sb.AppendLine("	/// </summary>");
		//    sb.AppendLine("	[EdmComplexTypeAttribute(NamespaceName=\"" + this.GetLocalNamespace() + ".Entity" + "\", Name=\"" + table.PascalName + "Wrapper\")]");
		//    sb.AppendLine("	[DataContractAttribute(IsReference = true)]");
		//    sb.AppendLine("	[Serializable()]");
		//    sb.AppendLine("	public partial class " + table.PascalName + "Wrapper : ComplexObject, " + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + "Wrapper");
		//    sb.AppendLine("	{");
		//    sb.AppendLine("		private " + table.PascalName + "Constants _status;");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// The numeric value associated with the type");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		[EdmScalarPropertyAttribute(EntityKeyProperty = false, IsNullable = false)]");
		//    sb.AppendLine("		[DataMemberAttribute()]");
		//    sb.AppendLine("		public int Value");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			get { return (int)_status; }");
		//    sb.AppendLine("			set { _status = (" + table.PascalName + "Constants)value; }");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Serves as a hash function for a particular type.");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public override int GetHashCode()");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			return base.GetHashCode();");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// The enum value associated with the type");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public " + table.PascalName + "Constants EnumValue");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			get { return _status; }");
		//    sb.AppendLine("			set { _status = value; }");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Convert the enum to a wrapper object");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public static implicit operator");
		//    sb.AppendLine("				" + table.PascalName + "Wrapper(" + table.PascalName + "Constants status)");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			return new " + table.PascalName + "Wrapper { EnumValue = status };");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Convert a wrapper object into its associated integer value");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public static implicit operator");
		//    sb.AppendLine("				int(" + table.PascalName + "Wrapper statusWrapper)");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			return (int)statusWrapper.EnumValue;");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Convert a wrapper object into its associated enum value");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public static implicit operator");
		//    sb.AppendLine("				" + table.PascalName + "Constants(" + table.PascalName + "Wrapper statusWrapper)");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			return statusWrapper.EnumValue;");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Test two wrapper objects for equality");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public static bool operator ==(" + table.PascalName + "Wrapper a, " + table.PascalName + "Wrapper b)");
		//    sb.AppendLine("		{");
		//    //sb.AppendLine("			if (a.EnumValue == null && b.EnumValue == null)");
		//    //sb.AppendLine("				return true;");
		//    //sb.AppendLine("			else if (a.EnumValue == null || b.EnumValue == null)");
		//    //sb.AppendLine("				return false;");
		//    sb.AppendLine("			return a.EnumValue == b.EnumValue;");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Test two wrapper objects for inequality");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public static bool operator !=(" + table.PascalName + "Wrapper a, " + table.PascalName + "Wrapper b)");
		//    sb.AppendLine("		{");
		//    //sb.AppendLine("			if (a.EnumValue == null && b.EnumValue == null)");
		//    //sb.AppendLine("				return false;");
		//    //sb.AppendLine("			else if (a.EnumValue == null || b.EnumValue == null)");
		//    //sb.AppendLine("				return true;");
		//    sb.AppendLine("			return a.EnumValue != b.EnumValue;");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		/// <summary>");
		//    sb.AppendLine("		/// Compare a wrapper objects for equality against the current instance");
		//    sb.AppendLine("		/// </summary>");
		//    sb.AppendLine("		public override bool Equals(object obj)");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			if (obj == null)");
		//    sb.AppendLine("				return false;");
		//    sb.AppendLine("			" + table.PascalName + "Wrapper ptw = obj as " + table.PascalName + "Wrapper;");
		//    sb.AppendLine("			if (ptw == null)");
		//    sb.AppendLine("				return false;");
		//    sb.AppendLine("			else");
		//    sb.AppendLine("				return this.EnumValue == ptw.EnumValue;");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();

		//    //Add EF Interfaces
		//    sb.AppendLine("		#region I" + table.PascalName + " Members");
		//    sb.AppendLine();
		//    sb.AppendLine("		System.Enum " + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + "Wrapper.EnumValue");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			get { return this.EnumValue; }");
		//    sb.AppendLine("			set { this.EnumValue = (" + this.GetLocalNamespace() + "." + table.PascalName + "Constants)value; }");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		int " + this.GetLocalNamespace() + ".Interfaces.Entity.I" + table.PascalName + "Wrapper.Value");
		//    sb.AppendLine("		{");
		//    sb.AppendLine("			get { return this.Value; }");
		//    sb.AppendLine("			set { this.Value = value; }");
		//    sb.AppendLine("		}");
		//    sb.AppendLine();
		//    sb.AppendLine("		#endregion");
		//    sb.AppendLine();

		//    sb.AppendLine("	}");
		//    sb.AppendLine();
		//  }

		//  sb.AppendLine("	#endregion");
		//  sb.AppendLine();

		//}
		#endregion

		private void AppendTypeTableEnums()
		{
			try
			{
				foreach (var table in _model.Database.Tables.Where(x => x.Generated && x.IsTypeTable).OrderBy(x => x.Name))
				{
					if (table.IsTypeTable && table.PrimaryKeyColumns.Count == 1)
					{
						sb.AppendLine("	#region StaticDataConstants Enumeration for '" + table.PascalName + "' entity");
						sb.AppendLine("	/// <summary>");
						sb.AppendLine("	/// Enumeration to define static data items and their ids '" + table.PascalName + "' table.");
						sb.AppendLine("	/// </summary>");
						sb.AppendLine("	public enum " + table.PascalName + "Constants");
						sb.AppendLine("	{");
						foreach (RowEntry rowEntry in table.StaticData)
						{
							var idValue = rowEntry.GetCodeIdValue(table);
							var identifier = rowEntry.GetCodeIdentifier(table);
							var description = rowEntry.GetCodeDescription(table);
							if (!string.IsNullOrEmpty(description))
							{
								sb.AppendLine("		/// <summary>");
								sb.AppendLine("		/// " + description);
								sb.AppendLine("		/// </summary>");
								sb.AppendLine("		[Description(\"" + description + "\")]");
							}
							else
							{
								sb.AppendLine("		/// <summary>");
								sb.AppendLine("		/// Enumeration for the '" + identifier + "' item");
								sb.AppendLine("		/// </summary>");
								sb.AppendLine("		[Description(\"" + description + "\")]");
							}

							var key = ValidationHelper.MakeDatabaseIdentifier(identifier.Replace(" ", ""));
							if ((key.Length > 0) && ("0123456789".Contains(key[0])))
								key = "_" + key;

							sb.AppendLine("		" + key + " = " + idValue + ",");
						}
						sb.AppendLine("	}");
						sb.AppendLine("	#endregion");
						sb.AppendLine();
					}
				}
			}
			catch (Exception ex)
			{
				throw;
			}

		}

		#endregion

	}
}